package qos.estimator.fuzzy;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;

public class RuleGenerator {

	protected Set<String> rules = new HashSet<String>();
	private double memoryPercentual = 0d;
	private double cpuSoftPercentual = 0d;
	private double cpuIOWaitPercentual = 0d;
	private double cpuUsrPercentual = 0d;
	private double cpuSysPercentual = 0d;
	private double residentSetSize = 0d;
	private double virtualSize = 0d;
	private double majorFaultsPerSecond = 0d;
	private double minorFaultsPerSecond = 0d;
	private double interruptionsPerSecond = 0d;
	private double diskUsage = 0d;
	private double elapsedTime = 0d;
	private double concSessions = 0d;
	private double locks = 0d;
	private double buffers = 0d;
	private FuzzyEstimator estimator;
	protected Map<String, Integer> rulesCount = new HashMap<String, Integer>();
	
	public RuleGenerator(FuzzyEstimator estimator) {
		this.estimator = estimator;
	}
	
	private void readStatisticsFromFile() {
		try {
			FileReader reader = new FileReader("stats/qosdb.stats");
			BufferedReader bufferedReader = new BufferedReader(reader);
			String line = bufferedReader.readLine();
			System.out.print("Creating rules from training set...");
			int size = 0;
			while (line != null){
				loadAttributesFromStatistics(line);
				line = bufferedReader.readLine();
				size++;
			}
			System.out.println("done. "+ rules.size()+" were read.");
			bufferedReader.close();
			reader.close();
			
		} catch (FileNotFoundException e) {
			System.err.println("File not found.");
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Could not read rules from the specified file.");
			e.printStackTrace();
		} 
	}
	
	public Collection<String> generateRulesFromFile(){
		readStatisticsFromFile();
		printHistogram();
		return rules;
	}
	
	public Collection<String> generateRulesFromCollection(Collection<String> statisticsCollection){
		System.out.println("Creating rules from training set...");
		for (String line : statisticsCollection) {
			loadAttributesFromStatistics(line);
		}
		return rules;
	}

	private void loadAttributesFromStatistics(String line) {
		StringTokenizer result = new StringTokenizer(line, "\t");
		if( result.countTokens() != 0 ) {
			result.nextToken(); //discarding %steal
			residentSetSize = Double.parseDouble(result.nextToken());
			result.nextToken(); //discarding %guest
			majorFaultsPerSecond = Double.parseDouble(result.nextToken());
			cpuIOWaitPercentual = Double.parseDouble(result.nextToken());
			cpuSoftPercentual = Double.parseDouble(result.nextToken());
			cpuUsrPercentual = Double.parseDouble(result.nextToken());
			memoryPercentual = Double.parseDouble(result.nextToken());
			diskUsage = Double.parseDouble(result.nextToken());
			virtualSize = Double.parseDouble(result.nextToken());
			minorFaultsPerSecond = Double.parseDouble(result.nextToken());
			interruptionsPerSecond = Double.parseDouble(result.nextToken());
			cpuSysPercentual = Double.parseDouble(result.nextToken());
			concSessions     = Double.parseDouble( result.nextToken());
			locks            = Double.parseDouble(result.nextToken());
			buffers          = Double.parseDouble(result.nextToken());
			result.nextToken(); //discarding %nice
			elapsedTime = Double.parseDouble(result.nextToken());

			String rule = buildRule();
			rule = rule.substring(0, rule.indexOf("then"));
			Integer times = rulesCount.get(rule);
			if(times == null){
				rulesCount.put(rule, 1);
			}else{
				rulesCount.put(rule, ++times);
			}
		}
	}
	
	private void printHistogram() {
		int max = 0;
		for (Iterator<Entry<String, Integer>> iterator = rulesCount.entrySet().iterator(); iterator.hasNext();) {
			Entry<String, Integer> rule = iterator.next();
			System.out.println("rule: "+rule.getKey()+" occurred "+rule.getValue()+" times.");
			max = Math.max(max, rule.getValue());
		}
		
		
		
		System.out.println("From a total of "+rules.size()+ " rules, there were "+rulesCount.size()+" distinct rules.");
		System.out.println("The higher number of repetitions was: "+max);
	}

	public String buildRule() {
		String ruleTemplate = "if memoryPercentual is {0} and cpuSoftPercentual is {1} and cpuIOWaitPercentual is {2} " +
				"and cpuUsrPercentual is {3} and cpuSysPercentual is {4} and residentSetSize is {5} " +
				"and virtualSize is {6} and majorFaultsPerSecond is {7} and minorFaultsPerSecond is {8} and interruptionsPerSecond is {9} " +
				"and diskUsage is {10} and concSessions is {11} and locks is {12} and buffers is {13} then elapsedTime is {14}";
		String residentSetSizeLabel = estimator.getResidentSetSizeLabel(residentSetSize);
		String majorFaultsPerSecondLabel = estimator.getMajorFaultsPerSecondLabel(majorFaultsPerSecond);
		String cpuIOWaitPercentualLabel = estimator.getCpuIOWaitPercentualLabel(cpuIOWaitPercentual);
		String cpuSoftPercentualLabel = estimator.getCpuSoftPercentualLabel(cpuSoftPercentual);
		String cpuUsrPercentualLabel = estimator.getCpuUsrPercentualLabel(cpuUsrPercentual);
		String memoryPercentualLabel = estimator.getMemoryPercentualLabel(memoryPercentual);
		String diskUsageLabel = estimator.getDiskUsageLabel(diskUsage);
		String virtualSizeLabel = estimator.getVirtualSizeLabel(virtualSize);
		String minorFaultsPerSecondLabel = estimator.getMinorFaultsPerSecondLabel(minorFaultsPerSecond);
		String interruptionsPerSecondLabel = estimator.getInterruptionsPerSecondLabel(interruptionsPerSecond);
		String cpuSysPercentualLabel = estimator.getCpuSysPercentualLabel(cpuSysPercentual);
		String elapsedTimeLabel = estimator.getElapsedTimeLabel(elapsedTime);
		String concSessionsLabel = estimator.getConcSessionsLabel( concSessions );
		String locksLabel = estimator.getLocksLabel(locks);
		String bufferLabel = estimator.getBuffersLabel( buffers );

		
		String rule = MessageFormat.format(ruleTemplate, memoryPercentualLabel, cpuSoftPercentualLabel, cpuIOWaitPercentualLabel, 
				cpuUsrPercentualLabel, cpuSysPercentualLabel, residentSetSizeLabel, virtualSizeLabel, majorFaultsPerSecondLabel, 
				minorFaultsPerSecondLabel, interruptionsPerSecondLabel, diskUsageLabel,	concSessionsLabel, locksLabel, bufferLabel, 
				elapsedTimeLabel);
		rules.add(rule);
		
		return rule;
	}
	
	public void setValues(ClassificationTuple classificationTuple){
		residentSetSize = classificationTuple.getResidentSetSize();
		majorFaultsPerSecond = classificationTuple.getMajorFaultsPerSecond();
		cpuIOWaitPercentual = classificationTuple.getCpuIOWaitPercentual();
		cpuSoftPercentual = classificationTuple.getCpuSoftPercentual();
		cpuUsrPercentual = classificationTuple.getCpuUsrPercentual();
		memoryPercentual = classificationTuple.getMemoryPercentual();
		diskUsage = classificationTuple.getDiskUsage();
		virtualSize = classificationTuple.getVirtualSize();
		minorFaultsPerSecond = classificationTuple.getMinorFaultsPerSecond();
		interruptionsPerSecond = classificationTuple.getInterruptionsPerSecond();
		cpuSysPercentual = classificationTuple.getCpuSysPercentual();
		concSessions     = classificationTuple.getConcSessions();
		locks            = classificationTuple.getLocks();
		buffers          = classificationTuple.getBuffers();
		elapsedTime 	 = classificationTuple.getElapsedTime();
	}

}
